题目描述:
代码实现二叉树的后续遍历。要求:1、不可以用递归;2、不可以用栈;3、自定义树节点的结构;4、给出测试用例;5、语言不限;
注意:你的方法的输入为根节点
输入描述:
第一行一个正整数n(1<=n<=100),表示二叉树有n个结点。
接下来n行,第i行两个整数li,ri (0<=li,ri<=n) ,分别表示第i个结点的左儿子和右儿子,为0代表空。
保证根为1,保证输入为合法二叉树。
输出描述:
输出一行。输出n个数,代表后序遍历的结点的顺序,相邻两个数之间用一个空格相隔。
大致思路如下,关于输入输出处理,在我另一篇关于二叉树的博客里有写:
非递归实现二叉树遍历
因为不能用栈,所以对节点做调整,加入父节点属性。
现在有父节点,我们再来看后序遍历的顺序。首先父节点,然后向左寻找,找到左节点,然后回到该节点的上一个节点,再找其右节点,再回到该节点的上一个节点。
那么起码要知道,上一节点是谁。并且实时调整上一节点。
所以假设,我们设置一个当前节点指针pCur,一个上一节点指针pLast。
每一次结束,当前指针一定是指向父节点,上一节点指针一定是指向当前指针的上一个位置。
所以存在两者情况,要么,上一节点指针指向当前指针的左节点,要么指向右节点。
所以简化成最简单的情况,
- pLast == pCur.left
- pLast == pCur.right
第一种情况,由于当前while循环寻找到的一定是叶节点,则左节点一定为空,如果同时右节点存在,那么说明存在左子树,需要遍历右子树,并判断右子树是否存在左节点,这时就是重复寻找。如果不存在右子树,则直接输出当前指针指向的节点,然后回退父节点,输出父节点,回退父节点后,不需要再遍历左节点,因为左节点此时为空,所以下一轮寻找会直接判断右节点为空,即不存在右子树,输出当前节点并回退父节点。
第二种情况,说明当前遍历到右节点,则一定是右子树遍历完毕遍历到右叶子节点,所以输出,并回退父节点。
讲的有点混乱,我还是要再琢磨一下怎么更好的阐述。。。
总之就是对于一个节点,其是否有左子树,如果有左子树,则继续沿左子树方向找到左叶子节点;如果没有左子树,看是否有右子树,有右子树,则继续将右子树当作一个二叉树进行遍历;
如果有左叶子节点就输出左叶子节点,然后看有没有右子树,如果有则继续将右子数当作二叉树遍历;
如果只有右叶子节点,则输出右叶子节点;
然后回退,输出父节点。
如何判断叶子节点,则需要每次寻找子树后,如果存在子树,则需要继续沿左一直找到左叶子节点,或一直找右叶子节点。如果没有右子树或左子树,则可以输出。
所以本解法在没有左节点,只有右叶子节点时continue,没有继续内部while循环找叶子节点。只有在判断有子树的情况下,没有continue;
1 | var node = function (val) { |